﻿using System.ComponentModel;
using System.Reflection;
using System.Linq;
using System.Collections;
using System.Collections.Generic;
using System.Windows.Controls.Primitives;
using System.Windows.Automation;

// Author: Miroslav Matula m.matula@alutam.cz 
// Date : 31/8/2010

namespace System.Windows.Controls
{
  /// <summary>
  /// Is base control for DataGridToolBar and DataGridTooolBarRIA.
  /// 
  /// </summary>
  [TemplatePart(Name = DATAGRIDTOOL_elementBuAddNew, Type = typeof(ButtonBase))]
	[TemplatePart(Name = DATAGRIDTOOL_elementBuEdit, Type = typeof(ButtonBase))]
	[TemplatePart(Name = DATAGRIDTOOL_elementBuRemove, Type = typeof(ButtonBase))]
	[TemplatePart(Name = DATAGRIDTOOL_elementBuFilter, Type = typeof(ButtonBase))]
	[TemplatePart(Name = DATAGRIDTOOL_elementBuClearFilter, Type = typeof(ButtonBase))]
	[TemplatePart(Name = DATAGRIDTOOL_elementBuRefresh, Type = typeof(ButtonBase))]
	[TemplatePart(Name = DATAGRIDTOOL_elementBuSave, Type = typeof(ButtonBase))]
	[TemplatePart(Name = DATAGRIDTOOL_elementBuCancel, Type = typeof(ButtonBase))]
  [TemplatePart(Name = DATAGRIDTOOL_elementBuRejectChanges, Type = typeof(ButtonBase))]
  [TemplatePart(Name = DATAGRIDTOOL_elementFilterMessage, Type = typeof(TextBlock))]
  [TemplatePart(Name = DATAGRIDTOOL_elementStateMessage, Type = typeof(TextBlock))]
  public abstract class DataGridToolBarBase : ContentControl
	{
		#region Constants

		// Automation Id constants
		private const string DATAGRIDTOOL_BuAddRowTextBoxAutomationId = "AddNew";
		private const string DATAGRIDTOOL_BuEditTextBoxAutomationId = "Edit";
		private const string DATAGRIDTOOL_BuDeleteRowTextBoxAutomationId = "Remove";
		private const string DATAGRIDTOOL_BuFilterTextBoxAutomationId = "Filter";
		private const string DATAGRIDTOOL_BuClearFilterTextBoxAutomationId = "ClearFilter";
		private const string DATAGRIDTOOL_BuRefreshTextBoxAutomationId = "Refresh";
		private const string DATAGRIDTOOL_BuSaveTextBoxAutomationId = "Save";
    private const string DATAGRIDTOOL_BuCancelTextBoxAutomationId = "Cancel";
    private const string DATAGRIDTOOL_BuRejectChangesTextBoxAutomationId = "RejectChanges";
		// Parts constants
		private const string DATAGRIDTOOL_elementBuEdit = "EditButton";
		private const string DATAGRIDTOOL_elementBuAddNew = "AddNewButton";
		private const string DATAGRIDTOOL_elementBuRemove = "RemoveButton";
		private const string DATAGRIDTOOL_elementBuFilter = "FilterButton";
		private const string DATAGRIDTOOL_elementBuClearFilter = "ClearFilterButton";
		private const string DATAGRIDTOOL_elementBuRefresh = "RefreshButton";
		private const string DATAGRIDTOOL_elementBuSave = "SaveButton";
    private const string DATAGRIDTOOL_elementBuCancel = "CancelButton";
    private const string DATAGRIDTOOL_elementBuRejectChanges = "RejectChangesButton";
		private const string DATAGRIDTOOL_elementFilterMessage = "FilterMessage";
    private const string DATAGRIDTOOL_elementStateMessage = "StateMessage";

		#endregion

		#region Ctor
    /// <summary>
    /// Constructor 
    /// </summary>
		public DataGridToolBarBase()
		{
      _contentLoaded = false;
      this.DefaultStyleKey = typeof(DataGridToolBarBase);

			ColumnsForFiltering = new List<DataGridToolBarFilterItem>();
			ColumnsForFilteringInternal = new List<DataGridToolBarFilterItemInternal>();
			Filter = new List<DataGridToolBarFilterItemDef>();
			//default values
			AutoGenerateFilter = true;
			UseQuestionMessage = true;
			AutoSubmit = true;
			ButtonAddNewVisible = true;
			ButtonRemoveVisible = true;
			ButtonEditVisible = true;
			ButtonRefreshVisible = true;
      SetFlag(InnerFlags.buAll, true);
		}

		#endregion


		#region -- Abstract --
		/// <summary>
		/// Is True if DataGrid.ItemsSource has changes.
		/// </summary>
		public abstract bool DataHasChanges { get; }
    /// <summary>
    /// Here is an implementaion of filtering. It is made according to the definition in Filter.
    /// </summary>
		public abstract void ApplyFiltr();

		#endregion

		#region -- Inbuild controls ---------------------------
    /// <summary>
    /// Adds a new item. Invoke a data form if the event CreateDataForm is not empty. 
    /// </summary>
		public ButtonBase ButtonAddNew { get; protected set; }
    /// <summary>
    /// Edits the DataGrid.SelectedItem. Invoke a data form if the event CreateDataForm is not empty. 
    /// </summary>
    public ButtonBase ButtonEdit { get; protected set; }
    /// <summary>
    /// Removes the DataGrid.SelectedItem from the DataGrid.ItemsSource
    /// </summary>
		public ButtonBase ButtonRemove { get; protected set; }
    /// <summary>
    /// Invokes the filtr form.  
    /// </summary>
		public ButtonBase ButtonFilter { get; protected set; }
    /// <summary>
    /// Clears the filter definition.
    /// </summary>
		public ButtonBase ButtonClearFilter { get; protected set; }
    /// <summary>
    /// Refreshes data. It works only if a data source is a RIA Services.
    /// </summary>
		public ButtonBase ButtonRefresh { get; protected set; }
    /// <summary>
    /// Saves data changes.
    /// </summary>
		public ButtonBase ButtonSave { get; protected set; }
    /// <summary>
    /// Cancels data changes.
    /// </summary>
		public ButtonBase ButtonCancel { get; protected set; }
    /// <summary>
    /// Displays a filter as a user text  
    /// </summary>
    public TextBlock FilterMessage { get; protected set; }
    /// <summary>
    /// Displays a state message  
    /// </summary>
    public TextBlock StateMessage { get; protected set; }
    /// <summary>
    /// Reject changes.
    /// </summary>
    public ButtonBase ButtonRejectChanges { get; protected set; }

		#endregion

		#region -- Fields ---------------------------------------------

		// Popup okno pro zadání filtrovacích parametrů
		private Primitives.Popup _filterParametrPopup;
		// počítadlo, > 0 - edituje se cell v datagridu
		private int _isCellEditing = 0;
		//
		private DataGridTextColumn _lastFilteredColumn;
    //
    private bool _contentLoaded;
    private string _errorMessage=null;

		#endregion

		#region -- properties  ----------------------
    /// <summary>
    /// Inbuilt flag IsBusy. It is second indicator IsBusy, because some a data controls has a implementation mistake in the property IsBusy.
    /// </summary>
    protected int IsBusyCnt
    {
      get { return _isBusyCnt; }
      set {
        if(_isBusyCnt == value) return;
        _isBusyCnt = value;
        StateMessage.Text = GetMessageState();
        SetInbuiltButtons();
      }
    }
    private int _isBusyCnt;
		/// <summary>
    /// The Brush of filter.oterator in the text FilterMessage.
		/// </summary>
		public Media.Brush MessageOperatorBrush
		{
			get
			{
				if(_messageOperatorBrush == null) _messageOperatorBrush = new Media.SolidColorBrush(Media.Colors.Red);
				return _messageOperatorBrush;
			}
			set
			{
				_messageOperatorBrush = value;
			}
		}
    private Media.Brush _messageOperatorBrush;
    /// <summary>
    /// The Brush of filter.text in the text FilterMessage.
		/// </summary>
		public Media.Brush MessageValueBrush
		{
			get
			{
				if(_messageValueBrush == null) _messageValueBrush = new Media.SolidColorBrush(Media.Colors.Blue);
				return _messageValueBrush;
			}
			set
			{
				_messageValueBrush = value;
			}
		}
    private Media.Brush _messageValueBrush;
    /// <summary>
		/// Sets visibility of the button Edit.
		/// </summary>
		public bool ButtonEditVisible
		{
			get { return _buttonEditVisible; }
			set
			{
				_buttonEditVisible = value;
				if(ButtonEdit != null) if(value) ButtonEdit.Visibility = Windows.Visibility.Visible; else ButtonEdit.Visibility = Windows.Visibility.Collapsed;
			}
		}
    private bool _buttonEditVisible = false;
    /// <summary>
		/// Sets visibility of the button AddNew.
		/// </summary>
		public bool ButtonAddNewVisible
		{
			get { return _buttonAddNewVisible; }
			set
			{
				_buttonAddNewVisible = value;
				if(ButtonAddNew != null) if(value) ButtonAddNew.Visibility = Windows.Visibility.Visible; else ButtonAddNew.Visibility = Windows.Visibility.Collapsed;
			}
		}
    private bool _buttonAddNewVisible = false;
    /// <summary>
		/// Sets visibility of the button Remove. 
		/// </summary>
		public bool ButtonRemoveVisible
		{
			get { return _buttonRemoveVisible; }
			set
			{
				_buttonRemoveVisible = value;
				if(ButtonRemove != null) if(value) ButtonRemove.Visibility = Windows.Visibility.Visible; else ButtonRemove.Visibility = Windows.Visibility.Collapsed;
			}
		}
    private bool _buttonRemoveVisible = false;
    /// <summary>
		/// Sets visibility of the button Filter.
		/// </summary>
		public bool ButtonFilterVisible
		{
			get { return _buttonFilterVisible; }
			set
			{
				_buttonFilterVisible = value;
				if(ButtonFilter != null) {
					if(value) {
						ButtonFilter.Visibility = Windows.Visibility.Visible;
						ButtonClearFilter.Visibility = Windows.Visibility.Visible;
					} else {
						ButtonFilter.Visibility = Windows.Visibility.Collapsed;
						ButtonClearFilter.Visibility = Windows.Visibility.Collapsed;
					}
				}
			}
		}
    private bool _buttonFilterVisible = true;
    /// <summary>
		/// Sets visibility of the button Refresh.
		/// </summary>
		public bool ButtonRefreshVisible
		{
			get { return _buttonRefreshVisible; }
			set
			{
				_buttonRefreshVisible = value;
				if(ButtonRefresh != null) if(value) ButtonRefresh.Visibility = Windows.Visibility.Visible; else ButtonRefresh.Visibility = Windows.Visibility.Collapsed;
			}
		}
    private bool _buttonRefreshVisible = true;
    /// <summary>
		/// If it is true, the control shows QuestionMessageBox before it starts the remove item method.
		/// </summary>
		public bool UseQuestionMessage { get; set; }

		/// <summary>
		///  If it is true, all columns in DataGrid can be filtered.
		/// </summary>
		public bool AutoGenerateFilter { get; set; }
		/// <summary>
    /// You can define own list columns which can be used for filtering, 
    /// </summary>
    /// <example>
    /// <code>
    ///	<DataGridToolBarBase.ColumnsForFiltering>
		///		<DataGridToolBarFilterItem ColumnName="CompanyName"  />
		///		<DataGridToolBarFilterItem ColumnName="FirstName"  />
		///		<DataGridToolBarFilterItem ColumnName="LastName"  />
		///	</DataGridToolBarBase.ColumnsForFiltering>
    ///	</code>
    /// </example>
		public List<DataGridToolBarFilterItem> ColumnsForFiltering { get; private set; }
		// inner definition of Filtr
		private List<DataGridToolBarFilterItemInternal> ColumnsForFilteringInternal { get; set; }
		// Definice filtru. Zadané přes Popup okno
		protected List<DataGridToolBarFilterItemDef> Filter { get; set; }

    /// <summary>
    /// Contains a DataForm instance from the event CreateDataForm.
    /// </summary>
		protected ChildWindow DataFormWindow {get; private set;}

		#endregion

		#region -- DependencyProperties ----------------------------------------

		/// <summary>
		/// Reference to DataGrid.
		/// </summary>
    /// <example>XAML
    /// <code>
    /// DataGrid="{ Binding ElementName=dataGridNameControl, Mode=OneTime}"
    /// </code>
    /// </example>
		public DataGrid DataGrid
		{
			get { return (DataGrid)GetValue(DataGridProperty); }
			set { SetValue(DataGridProperty, value); }
		}
		public static readonly DependencyProperty DataGridProperty =
				DependencyProperty.Register("DataGrid", typeof(DataGrid), typeof(DataGridToolBarBase), new PropertyMetadata(null, new PropertyChangedCallback(OnDataGridChanged)));

		private static void OnDataGridChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
		{
			if(e.OldValue != null) ((DataGridToolBarBase)d).DetachDataGrid((DataGrid)e.OldValue);
			((DataGridToolBarBase)d).AttachDataGrid((DataGrid)e.NewValue);
		}

		/// <summary> 
		/// Private property z abych mohl udělat Binding na DataGrid.ItemsSource a odchytil změnu. Podle toho nastavuji buttony CanAddNew a CanRemove
		/// </summary>
		public static readonly DependencyProperty ItemsSourceProperty =
			DependencyProperty.Register("ItemsSource", typeof(object), typeof(DataGridToolBarBase),
			new PropertyMetadata(null, new PropertyChangedCallback(OnItemsSourceChanged)));

		private static void OnItemsSourceChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
		{
			DataGridToolBarBase dgtb = (DataGridToolBarBase)d;

			dgtb.InitInbuiltControls(dgtb.DataGrid);
		}
    /// <summary>
    /// The property is bindings to ItemsSource.Busy. For example when the  LoadData method or a SubmitChanges method are invoked.
    /// </summary>
		public bool IsBusy
		{
      get { return (bool)GetValue(IsBusyProperty) || _isBusyCnt>0; }
		}
		public static readonly DependencyProperty IsBusyProperty =
				DependencyProperty.Register("IsBusy", typeof(bool), typeof(DataGridToolBarBase), new PropertyMetadata(false, new PropertyChangedCallback(OnIsBusyChanged)));

		private static void OnIsBusyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
		{
      DataGridToolBarBase dg = (DataGridToolBarBase)d;
			dg.SetInbuiltButtons();
      if(dg._contentLoaded) dg.StateMessage.Text = dg.GetMessageState();
		}
    /// <summary>
    ///  The property is bindings to DomainDataSource.CanLoad. 
    /// </summary>
		public bool CanLoad
		{
			get { return (bool)GetValue(CanLoadProperty); }
		}
		public static readonly DependencyProperty CanLoadProperty =
				DependencyProperty.Register("CanLoad", typeof(bool), typeof(DataGridToolBarBase), new PropertyMetadata(true, new PropertyChangedCallback(OnCanLoadChanged)));

		private static void OnCanLoadChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
		{
			DataGridToolBarBase dgtb = (DataGridToolBarBase)d;
      dgtb.SetInbuiltButtons();
		}

		/// <summary>
    /// If is true the data changes are automaticaly saved.
		/// </summary>
		public bool AutoSubmit
		{
			get { return (bool)GetValue(AutoSubmitProperty); }
			set { SetValue(AutoSubmitProperty, value); }
		}
		public static readonly DependencyProperty AutoSubmitProperty =
				DependencyProperty.Register("AutoSubmit", typeof(bool), typeof(DataGridToolBarBase), new PropertyMetadata(true, new PropertyChangedCallback(OnAutoSubmitProperty)));

		private static void OnAutoSubmitProperty(DependencyObject d, DependencyPropertyChangedEventArgs e)
		{
			DataGridToolBarBase dgtb = (DataGridToolBarBase)d;
			dgtb.SetInbuiltButtons();
		}


		#endregion

		#region -- Event -------------------------------

		public event EventHandler<HandledEventArgs> Click_SubmitChanges;
		public event EventHandler<HandledEventArgs> Click_RejectChanges;
		public event EventHandler<HandledEventArgs> Click_Refresh;
		public event EventHandler<HandledEventArgs> Click_AddNew;
		public event EventHandler<HandledEventArgs> Click_Edit;
		public event EventHandler<HandledEventArgs> Click_Remove;
		public event EventHandler<HandledEventArgs> Click_Filter;
		public event EventHandler<HandledEventArgs> Click_ClearFilter;

		public event EventHandler<DataFormEventArgs> CreateDataForm;
		//public event EventHandler<HandledEventArgs> DataChanged;

		#endregion

		#region -- On ----------------------------------------------

    public string GetMessageState()
    {
      string message = _errorMessage;
      if(IsLoading) {
        message = LangResources.LocalizedStrings.DGTB_msg_loading;
        _errorMessage = null;
      } else if(IsSubmitting) {
        message = LangResources.LocalizedStrings.DGTB_msg_submitting;
        _errorMessage = null;
      }
      return message;
    }

    public abstract bool IsLoading { get; }

    public abstract bool IsSubmitting { get; }

		public virtual void OnRefreshData(HandledEventArgs arg)
		{
			if(Click_Refresh != null) {
				Click_Refresh(this, arg);
			}
		}

		public virtual void OnSubmitChanges(HandledEventArgs arg)
		{
			if(Click_SubmitChanges != null) {
				Click_SubmitChanges(this, arg);
			}
		}

		public virtual void OnRejectChanges(HandledEventArgs arg)
		{
			if(Click_RejectChanges != null) {
				Click_RejectChanges(this, arg);
			}
		}

		public virtual void OnFilter(HandledEventArgs arg)
		{
			if(Click_Filter != null) Click_Filter(this, arg);
		}

    public virtual void OnClearFilter(HandledEventArgs arg)
		{
			if(Click_ClearFilter != null) Click_ClearFilter(this, arg);
			if(!arg.Handled) {
				Filter.Clear();
				ApplyFiltr();
				FilterMessage.Inlines.Clear();
			}
		}

    public virtual void OnCancelLoadOrSubmitChanges()
    {
    }
    /// <summary>
    /// Removes DataGrid.SelectedItem. If you set arg.Handled=true in event Click_Remove, it means I do this by myself.
    /// </summary>
    /// <param name="arg"></param>
		public virtual void OnRemove(HandledEventArgs arg)
		{
			if(IsBusy) return;
			if(Click_Remove != null) Click_Remove(this, arg);
			if(arg.Handled || DataGrid == null) return;

			//--
			if(DataGrid.SelectedItem != null) {

				IEditableCollectionView ecv = null;
				IList list = null;
				if(DataGrid.ItemsSource is IEditableCollectionView) {
					ecv = DataGrid.ItemsSource as IEditableCollectionView;
				}else	if(DataGrid.ItemsSource is ICollectionView) {
					list = ((ICollectionView)DataGrid.ItemsSource).SourceCollection as IList;
				} else {
					list = DataGrid.ItemsSource as IList;
				}

				if((list == null && ecv==null) || (ecv != null && !ecv.CanRemove)) return;

				// question
					MessageBoxResult res = MessageBoxResult.OK;

					if(UseQuestionMessage) res = System.Windows.MessageBox.Show(LangResources.LocalizedStrings.DGBT_qs_remove, "", MessageBoxButton.OKCancel);
					if(MessageBoxResult.OK == res) {
						var ait = new object[DataGrid.SelectedItems.Count];
						int cnt = 0;
						foreach(var item in DataGrid.SelectedItems) {
							ait[cnt++] = item;
						}
            //todo: obsloužit Cancel
						//using(new DeferHelper(this)) {
							foreach(var item in ait) {
                  if(ecv != null) ecv.Remove(item);
                  else list.Remove(item);
							}
							// Submit
							if(AutoSubmit) {
								OnSubmitChanges(new HandledEventArgs());
							}
						//}
            //todo: nastav currentPosition
					}
			}
		}

    /// <summary>
    /// Invokes a data form if the event CreateDataForm is not empty. 
    /// If you set arg.Handled=true in event Click_AddNew, it means I do this by myself.
    /// </summary>
    /// <param name="arg"></param>
    public virtual void OnAddNewItem(HandledEventArgs arg)
		{
			if(IsBusy) return;
			if(Click_AddNew != null) Click_AddNew(this, arg);
			if(arg.Handled || DataGrid == null) return;

			//-- zabudovaný mechanizmus DataForm
			CreatePopupDataForm();
			DataFormWindow.Show();
			((IDataGridToolBar_DataFormWindow)DataFormWindow).AddNewItem();
		}
    /// <summary>
    /// Invokes a data form if the event CreateDataForm is not empty. 
    /// If you set arg.Handled=true in event Click_EditItem, it means I do this by myself.
    /// </summary>
    /// <param name="arg"></param>
    public virtual void OnEditItem(HandledEventArgs arg)
		{
			if(IsBusy) return;
			if(Click_Edit != null) Click_Edit(this, arg);
			if(arg.Handled || DataGrid == null || DataGrid.SelectedIndex == -1) return;
			CreatePopupDataForm();
			DataFormWindow.Show();
			((IDataGridToolBar_DataFormWindow)DataFormWindow).EditItem(DataGrid.SelectedItem);
		}

		void PopupDataForm_DataChanged(object sender, EventArgs e)
		{
			if(AutoSubmit) {
				OnSubmitChanges(new HandledEventArgs());
			} 
			IDataGridToolBar_DataFormWindow mw = DataFormWindow as IDataGridToolBar_DataFormWindow;
			if(mw.CallBackDataChanged != null) {
				mw.CallBackDataChanged(true);
			}
		}

		void PopupDataForm_Closed(object sender, EventArgs e)
		{
			IDataGridToolBar_DataFormWindow mw = sender as IDataGridToolBar_DataFormWindow;
			if(mw.DialogResult == true) {
			}
		}

		#endregion

		#region -- OnApplyTemplate -------------------------------------------

		/// <summary>
		/// Applies the control's template, retrieves the elements
		/// within it, and sets up events.
		/// </summary>
		public override void OnApplyTemplate()
		{
			base.OnApplyTemplate();
			// get new template parts
			//-- EditRow --------------------------
			if(ButtonEdit != null) ButtonEdit.Click -= new RoutedEventHandler(buEdit_Click);
			ButtonEdit = GetTemplateChild(DATAGRIDTOOL_elementBuEdit) as ButtonBase;
			if(ButtonEdit != null) {
				ButtonEdit.Click += new RoutedEventHandler(buEdit_Click);
				AutomationProperties.SetAutomationId(this.ButtonEdit, DATAGRIDTOOL_BuEditTextBoxAutomationId);
				if(ButtonEditVisible) {
					ButtonEdit.Visibility = Windows.Visibility.Visible;
				} else ButtonEdit.Visibility = Windows.Visibility.Collapsed;
			}
			//-- AddRow --------------------------
			if(ButtonAddNew != null) ButtonAddNew.Click -= new RoutedEventHandler(buAddNew_Click);
			ButtonAddNew = GetTemplateChild(DATAGRIDTOOL_elementBuAddNew) as ButtonBase;
			if(ButtonAddNew != null) {
				ButtonAddNew.Click += new RoutedEventHandler(buAddNew_Click);
				AutomationProperties.SetAutomationId(this.ButtonAddNew, DATAGRIDTOOL_BuAddRowTextBoxAutomationId);
				if(ButtonAddNewVisible) {
					ButtonAddNew.Visibility = Windows.Visibility.Visible;
				} else ButtonAddNew.Visibility = Windows.Visibility.Collapsed;
			}
			//-- DeleteRow --------------------------
			if(ButtonRemove != null) ButtonRemove.Click -= new RoutedEventHandler(buRemove_Click);
			ButtonRemove = GetTemplateChild(DATAGRIDTOOL_elementBuRemove) as ButtonBase;
			if(ButtonRemove != null) {
				ButtonRemove.Click += new RoutedEventHandler(buRemove_Click);
				AutomationProperties.SetAutomationId(this.ButtonRemove, DATAGRIDTOOL_BuDeleteRowTextBoxAutomationId);
				if(ButtonRemoveVisible) {
					ButtonRemove.Visibility = Windows.Visibility.Visible;
				} else ButtonRemove.Visibility = Windows.Visibility.Collapsed;
			}
			//-- Filter --------------------------
			if(ButtonFilter != null) ButtonFilter.Click -= new RoutedEventHandler(buFilter_Click);
			ButtonFilter = GetTemplateChild(DATAGRIDTOOL_elementBuFilter) as ButtonBase;
			if(ButtonFilter != null) {
				ButtonFilter.Click += new RoutedEventHandler(buFilter_Click);
				AutomationProperties.SetAutomationId(this.ButtonFilter, DATAGRIDTOOL_BuFilterTextBoxAutomationId);
				if(ButtonFilterVisible) ButtonFilter.Visibility = Windows.Visibility.Visible; else ButtonFilter.Visibility = Windows.Visibility.Collapsed;
			}
			//-- ClearFilter --------------------------
			if(ButtonClearFilter != null) ButtonClearFilter.Click -= new RoutedEventHandler(buClearFilter_Click);
			ButtonClearFilter = GetTemplateChild(DATAGRIDTOOL_elementBuClearFilter) as ButtonBase;
			if(ButtonClearFilter != null) {
				ButtonClearFilter.Click += new RoutedEventHandler(buClearFilter_Click);
				AutomationProperties.SetAutomationId(this.ButtonClearFilter, DATAGRIDTOOL_BuClearFilterTextBoxAutomationId);
				if(ButtonFilterVisible) ButtonClearFilter.Visibility = Windows.Visibility.Visible; else ButtonClearFilter.Visibility = Windows.Visibility.Collapsed;
			}
			//-- Refresh --------------------------
			if(ButtonRefresh != null) ButtonRefresh.Click -= new RoutedEventHandler(buRefresh_Click);
			ButtonRefresh = GetTemplateChild(DATAGRIDTOOL_elementBuRefresh) as ButtonBase;
			if(ButtonRefresh != null) {
				ButtonRefresh.Click += new RoutedEventHandler(buRefresh_Click);
				AutomationProperties.SetAutomationId(this.ButtonRefresh, DATAGRIDTOOL_BuRefreshTextBoxAutomationId);
				if(ButtonRefreshVisible) ButtonRefresh.Visibility = Windows.Visibility.Visible; else ButtonRefresh.Visibility = Windows.Visibility.Collapsed;
			}
			//-- Save --------------------------
			if(ButtonSave != null) ButtonSave.Click -= new RoutedEventHandler(buSave_Click);
			ButtonSave = GetTemplateChild(DATAGRIDTOOL_elementBuSave) as ButtonBase;
			if(ButtonSave != null) {
				ButtonSave.Click += new RoutedEventHandler(buSave_Click);
				AutomationProperties.SetAutomationId(this.ButtonSave, DATAGRIDTOOL_BuSaveTextBoxAutomationId);
			}
			//-- RejectChanges --------------------------
      if(ButtonRejectChanges != null) ButtonRejectChanges.Click -= new RoutedEventHandler(buRejectChanges_Click);
      ButtonRejectChanges = GetTemplateChild(DATAGRIDTOOL_elementBuRejectChanges) as ButtonBase;
      if(ButtonRejectChanges != null) {
        ButtonRejectChanges.Click += new RoutedEventHandler(buRejectChanges_Click);
        AutomationProperties.SetAutomationId(this.ButtonRejectChanges, DATAGRIDTOOL_BuRejectChangesTextBoxAutomationId);
			}
      //-- CancelRow --------------------------
      if(ButtonCancel != null) ButtonCancel.Click -= new RoutedEventHandler(buCancel_Click);
      ButtonCancel = GetTemplateChild(DATAGRIDTOOL_elementBuCancel) as ButtonBase;
      if(ButtonCancel != null) {
        ButtonCancel.Click += new RoutedEventHandler(buCancel_Click);
        AutomationProperties.SetAutomationId(this.ButtonCancel, DATAGRIDTOOL_BuCancelTextBoxAutomationId);
      }
      //-- FilterMessage ------------------------
			FilterMessage = GetTemplateChild(DATAGRIDTOOL_elementFilterMessage) as TextBlock;
      //-- StateMessage ------------------------
      StateMessage = GetTemplateChild(DATAGRIDTOOL_elementStateMessage) as TextBlock;
      _contentLoaded = true;
		}

		#endregion


		#region -- Show Inbuild controls ----------------------------

		[Flags]
		private enum InnerFlags : int
		{
      buAll = 0xFF,
      buAddNewIsEnable = 0x01,
			buRemoveIsEnable = 0x02,
			buFilterIsEnable = 0x04,
			buSaveCancelIsVisible = 0x08,
			buRefreshIsEnable = 0x10,
			buEditIsEnable = 0x20,
		}
		//----------
		private InnerFlags _flags = InnerFlags.buFilterIsEnable | InnerFlags.buRefreshIsEnable;
		//----------
		private void SetFlag(InnerFlags flags, bool value)
		{
			if(value) {
				this._flags = this._flags | flags;
			} else {
				this._flags = this._flags & ~flags;
			}
		}
		//----------
		private bool CheckFlag(InnerFlags flags)
		{
			return (this._flags & flags) != 0;
		}
    ////----------
    //protected void DoActionAccordingToFlags()
    //{
    //  if(_deferLevel != 0 ) return; // provedu v okamžiku DeferHelper.Dispose
    //  // proveď akci
    //  // buAdd
    //  if(ButtonAddNew!=null)ButtonAddNew.IsEnabled = CheckFlag(InnerFlags.buAddNewIsEnable);
    //  //buRemove
    //  if(ButtonEdit!=null)ButtonEdit.IsEnabled = CheckFlag(InnerFlags.buEditIsEnable);
    //  //buRemove
    //  if(ButtonRemove != null) ButtonRemove.IsEnabled = CheckFlag(InnerFlags.buRemoveIsEnable);
    //  //Filter
    //  if(ButtonFilter!=null)ButtonFilter.IsEnabled = ButtonClearFilter.IsEnabled = CheckFlag(InnerFlags.buFilterIsEnable);
    //  // Refresh
    //  if(ButtonRefresh!=null)ButtonRefresh.IsEnabled = CheckFlag(InnerFlags.buRefreshIsEnable);
    //  //Save
    //  if(ButtonCancel!=null)ButtonCancel.Visibility = ButtonSave.Visibility = (CheckFlag(InnerFlags.buSaveCancelIsVisible)) ? Visibility.Visible : Visibility.Collapsed;
    //  if(CheckFlag(InnerFlags.buSaveCancelIsVisible)) ButtonCancel.IsEnabled = ButtonSave.IsEnabled = true;
    //}

		#endregion

		#region -- Button.Click -------------------------------------

		//--  -------------------------------------
		void buAddNew_Click(object sender, RoutedEventArgs e)
		{
			OnAddNewItem(new HandledEventArgs());
		}
		//--  -------------------------------------
		void buEdit_Click(object sender, RoutedEventArgs e)
		{
			OnEditItem(new HandledEventArgs());
		}
		//-- -------------------------------------
		void buRemove_Click(object sender, RoutedEventArgs e)
		{
			OnRemove(new HandledEventArgs());
		}
		//-- -------------------------------------
		void buFilter_Click(object sender, RoutedEventArgs e)
		{
			ShowFilterParametrPopup("", null);
		}
		//-- -------------------------------------
		void buClearFilter_Click(object sender, RoutedEventArgs e)
		{
			OnClearFilter(new HandledEventArgs());
		}
		//-- RefreshRow -------------------------------------
		void buRefresh_Click(object sender, RoutedEventArgs e)
		{
			OnRefreshData(new HandledEventArgs());
		}
		//--  -------------------------------------
		void buSave_Click(object sender, RoutedEventArgs e)
		{
			OnSubmitChanges(new HandledEventArgs());
		}
		//--  -------------------------------------
		void buRejectChanges_Click(object sender, RoutedEventArgs e)
		{
			OnRejectChanges(new HandledEventArgs());
		}
    //--  -------------------------------------
    void buCancel_Click(object sender, RoutedEventArgs e)
    {
      OnCancelLoadOrSubmitChanges();
    }

		#endregion

		#region -- private Methods ---------------------------

    protected void SetMessageCancelled()
    {
      _errorMessage = LangResources.LocalizedStrings.DGTB_msg_canceled;
      StateMessage.Text = _errorMessage; 
    }
    protected void SetMessageError(string errorMessage_)
    {
      _errorMessage = LangResources.LocalizedStrings.DGTB_msg_error + ": " + errorMessage_;
      StateMessage.Text = _errorMessage; 
    }

		private void CreatePopupDataForm()
		{
			if(CreateDataForm==null) throw new Exception("Event DataGridToolBar.CreateDataForm is not defined");
			// only one instance
			if(DataFormWindow!=null) return;
		 // New popup
			var arg = new DataFormEventArgs();
			CreateDataForm(this, arg);
			if(arg.DataForm == null) throw new Exception("Error in Event CreateDataForm");
			/*
			DataFormWindow = new Popup();
			DataFormWindow.Child = arg.DataForm;
			*/
			DataFormWindow = (ChildWindow)arg.DataForm;
			IDataGridToolBar_DataFormWindow mw = arg.DataForm as IDataGridToolBar_DataFormWindow;
			if(mw == null) throw new Exception("DataForm must interface IDataForm_DGTB. Event DataGridToolBar.CreateDataForm");
			mw.ItemsSource = this.DataGrid.ItemsSource;
			mw.DataChanged += new EventHandler(PopupDataForm_DataChanged);
			mw.Closed += new EventHandler(PopupDataForm_Closed);
		}

		private void DetachDataGrid(DataGrid dg_)
		{
			// odstraní databinding
			this.ClearValue(ItemsSourceProperty);
			// odstrani eventy
			dg_.KeyDown -= new Input.KeyEventHandler(dg__KeyDown);
			dg_.PreparingCellForEdit -= new EventHandler<DataGridPreparingCellForEditEventArgs>(dg__PreparingCellForEdit);
			dg_.CellEditEnded -= new EventHandler<DataGridCellEditEndedEventArgs>(dg__CellEditEnded);
			dg_.RowEditEnded -= new EventHandler<DataGridRowEditEndedEventArgs>(dg__RowEditEnded);
      dg_.AutoGeneratingColumn -= dg__AutoGeneratingColumn;
    }
		//--------
		protected virtual void AttachDataGrid(DataGrid dg_)
		{
			dg_.KeyDown += new Input.KeyEventHandler(dg__KeyDown);
			dg_.PreparingCellForEdit += new EventHandler<DataGridPreparingCellForEditEventArgs>(dg__PreparingCellForEdit);
			dg_.CellEditEnded += new EventHandler<DataGridCellEditEndedEventArgs>(dg__CellEditEnded);
			dg_.RowEditEnded += new EventHandler<DataGridRowEditEndedEventArgs>(dg__RowEditEnded);
      dg_.AutoGeneratingColumn += dg__AutoGeneratingColumn;

			//-- povolené operace
			Data.Binding bi = new Data.Binding("ItemsSource");
			bi.Source = dg_;
			this.SetBinding(ItemsSourceProperty, bi);
			InitInbuiltControls(dg_);
		}

    void dg__AutoGeneratingColumn(object sender, DataGridAutoGeneratingColumnEventArgs e)
    {
      if(this.AutoGenerateFilter) InitInbuiltControls(this.DataGrid);
    }

		//-----------
    //private void SetButtonEdit_accessibility()
    //{
    //  bool tt = CreateDataForm != null;
    //  //if(DataGrid != null && DataGrid.ItemsSource is IEditableCollectionView) {
    //  //  IEditableCollectionView il = DataGrid.ItemsSource as IEditableCollectionView;
    //  //  tt = il.CanRemove;
    //  //}
    //  SetFlag(InnerFlags.buEditIsEnable, tt);
    //  DoActionAccordingToFlags();
    //}
		//-----------
    //private void SetButtonRemove_accessibility()
    //{
    //  //if(_buRemove == null) return;
    //  bool tt = true;
    //  if(DataGrid != null && DataGrid.ItemsSource is IEditableCollectionView) {
    //    IEditableCollectionView il = DataGrid.ItemsSource as IEditableCollectionView;
    //    tt = il.CanRemove;
    //  }
    //  //_buRemove.IsEnabled = tt;
    //  SetFlag(InnerFlags.buRemoveIsEnable, tt);
    //  DoActionAccordingToFlags();
    //}
		//------------
    //private void SetButtonAddNew_accessibility()
    //{
    //  bool tt = true;
    //  if(DataGrid != null && DataGrid.ItemsSource is IEditableCollectionView) {
    //    IEditableCollectionView il = DataGrid.ItemsSource as IEditableCollectionView;
    //    tt = il.CanAddNew;
    //  }
    //  SetFlag(InnerFlags.buAddNewIsEnable, tt);
    //  DoActionAccordingToFlags();
    //}
		//---------------
    //private void SetButtonsIsBusy(bool isBusy_)
    //{
    //  if(!_contentLoaded) return;
    //  if(isBusy_) {
    //    ButtonEdit.IsEnabled = false;
    //    ButtonAddNew.IsEnabled = false;
    //    ButtonRemove.IsEnabled = false;
    //    ButtonRefresh.IsEnabled = false;
    //    ButtonFilter.IsEnabled = false;
    //    ButtonClearFilter.IsEnabled = false;
    //    ButtonSave.IsEnabled = false;
    //  } else {
    //    DoActionAccordingToFlags();
    //  }
    //}
		//---------------
    //private void SetButtonsAccessibility()
    //{
    //  SetFlag(InnerFlags.buRefreshIsEnable, this.CanLoad);
    //  SetFlag(InnerFlags.buFilterIsEnable, this.CanLoad);
    //  SetFlag(InnerFlags.buSaveCancelIsVisible, DataHasChanges);
    //  DoActionAccordingToFlags();
    //}
    private bool? _dataGridIsReadOnly = null;
    private int _inbuiltButtonsState = -1;
    private void SetInbuiltButtons()
    {
      if(!_contentLoaded) return;
      int buttonsState = -1;
      if(IsBusy || IsBusyCnt > 0)
        buttonsState = 0;
      else if(this.DataHasChanges) buttonsState = 1;
      else buttonsState = 2;
      if(_inbuiltButtonsState == buttonsState) return; // není co měnit
      _inbuiltButtonsState = buttonsState;

      // Nejvyšší priorita IsBusy, IsEdit
      if(buttonsState == 0) {
        //
        DataGrid.IsHitTestVisible = false;
        if(_dataGridIsReadOnly == null) _dataGridIsReadOnly = DataGrid.IsReadOnly;
        DataGrid.IsReadOnly = true;
        ButtonCancel.Visibility = Windows.Visibility.Visible;
        ButtonRemove.IsEnabled = false;
        ButtonAddNew.IsEnabled = false;
        ButtonEdit.IsEnabled = false;
        ButtonRefresh.IsEnabled = false;
        ButtonFilter.IsEnabled = false;
        ButtonClearFilter.IsEnabled = false;
        ButtonSave.IsEnabled = false;
        ButtonRejectChanges.IsEnabled = false;
      }else {
        // not IsBusy 
        DataGrid.IsHitTestVisible = true;
        if(_dataGridIsReadOnly != null) {
          DataGrid.IsReadOnly = (bool)_dataGridIsReadOnly;
          _dataGridIsReadOnly = null;
        }
        ButtonCancel.Visibility = Windows.Visibility.Collapsed;
        ButtonRemove.IsEnabled = CheckFlag(InnerFlags.buRemoveIsEnable);
        ButtonAddNew.IsEnabled = CheckFlag(InnerFlags.buAddNewIsEnable);
        ButtonEdit.IsEnabled = CheckFlag(InnerFlags.buEditIsEnable);

        if(buttonsState == 1) {
          // has changes
          ButtonSave.IsEnabled = true;
          ButtonSave.Visibility = Windows.Visibility.Visible;
          ButtonRejectChanges.IsEnabled = true;
          ButtonRejectChanges.Visibility = Windows.Visibility.Visible;
          ButtonRefresh.IsEnabled = false;
          ButtonFilter.IsEnabled = false;
          ButtonClearFilter.IsEnabled = false;
        } else {
          // normal state
          ButtonSave.Visibility = Windows.Visibility.Collapsed;
          ButtonRejectChanges.Visibility = Windows.Visibility.Collapsed;
          ButtonRefresh.IsEnabled = CheckFlag(InnerFlags.buRefreshIsEnable);
          ButtonFilter.IsEnabled = CheckFlag(InnerFlags.buFilterIsEnable);
          ButtonClearFilter.IsEnabled = CheckFlag(InnerFlags.buFilterIsEnable);
        }
      }
    }
		//---------------
		private void InitInbuiltControls(DataGrid dg_)
		{
      SetInbuiltButtons();
      //-- povolené sloupce k filtrování -----------------
			if(ColumnsForFiltering.Count > 0) AutoGenerateFilter = false;
			ColumnsForFilteringInternal.Clear();
			foreach(var item in dg_.Columns) {
				if(item is DataGridTextColumn) {
					var col = (DataGridTextColumn)item;
					var fi1 = (ColumnsForFiltering.FirstOrDefault(p => p.ColumnName == col.Binding.Path.Path));
					if(AutoGenerateFilter || fi1 != null) {
						var fi = new DataGridToolBarFilterItemInternal();
						fi.ColumnName = col.Binding.Path.Path;
						if((fi1 != null) && !string.IsNullOrEmpty(fi1.Title)) fi.Title = fi1.Title;
						else if(col.Header is string) fi.Title = col.Header.ToString();
						ColumnsForFilteringInternal.Add(fi);
					}
				}
			}
		}
		//------------------
		void ShowFilterParametrPopup(string text_, DataGridToolBarFilterItemInternal fi_)
		{
			if(ColumnsForFilteringInternal.Count == 0) return;
			// test na dataTyp
			if(ColumnsForFilteringInternal[0].DataType == null && DataGrid != null && DataGrid.ItemsSource != null) {
				foreach(var item in DataGrid.ItemsSource) {
					Type columntype = item.GetType();
					foreach(var filtrDef in ColumnsForFilteringInternal) {
						PropertyInfo pi = columntype.GetProperty(filtrDef.ColumnName);
						filtrDef.DataType = pi.PropertyType;
					}
					break;	
				}
			}
			// create Popup
			if(_filterParametrPopup == null) {
				_filterParametrPopup = new Primitives.Popup();
				var fw = new DataGridToolBarControl.FilterParameterUC();
				fw.Language = this.Language;
				_filterParametrPopup.Child = fw;
				_filterParametrPopup.Closed += new EventHandler(_filterParametrPopup_Closed);
			}
			Media.GeneralTransform tt = DataGrid.TransformToVisual(null);
			var ll = tt.Transform(new Point(0, 0));
			// offset Y
			double dd = (DataGrid.ActualHeight - 100) / 2;
			if(dd < 0d) dd = 0d;
			_filterParametrPopup.VerticalOffset = dd + ll.Y; //_filterParametrPopup.ActualHeight
			// offset X
			dd = 0d;
			foreach(var co in DataGrid.Columns) {
				if(co == DataGrid.CurrentColumn) break;
				if(co.Visibility == Visibility.Visible) dd += co.ActualWidth;
			}
			_filterParametrPopup.HorizontalOffset = dd + ll.X;


			_filterParametrPopup.IsOpen = true;
			var ucFilterForm = _filterParametrPopup.Child as DataGridToolBarControl.FilterParameterUC;
			ucFilterForm.InitForm(ColumnsForFilteringInternal, fi_, text_);
		}
		//--------------
		void _filterParametrPopup_Closed(object sender, EventArgs e)
		{
			DataGrid.Focus();
			var ucFilterForm = _filterParametrPopup.Child as DataGridToolBarControl.FilterParameterUC;
			if(ucFilterForm.DialogResult == true) {
				if(!ucFilterForm.AddFilterDefToFilter)Filter.Clear();
				// uloží definici filtru
				string[] paterns;
				if(ucFilterForm.Operator == FilterOperator_DGTB.Contains) {
					paterns = ucFilterForm.txtValue.Text.Split(' ');
				} else {
					paterns = new string[] { ucFilterForm.txtValue.Text.Trim() };
				}

				foreach(var patern in paterns) {
					if(ucFilterForm.comOperator.SelectedItem != null && !string.IsNullOrEmpty(patern)) {
						Filter.Add(new DataGridToolBarFilterItemDef() {
							ColumnName = ucFilterForm.ColumnName,
							DataType = ucFilterForm.DataType,
							Title = ucFilterForm.Title,
							Value = patern,
							Operator = ucFilterForm.Operator,
							Mark = ucFilterForm.Mark
						});
					}
				}
				ApplyFiltr();
			}
		}
		//-- indikátor editace v datagridu -----------
		void dg__CellEditEnded(object sender, DataGridCellEditEndedEventArgs e)
		{
			_isCellEditing--;
		}
		//-- indikátor editace v datagridu -----------
		void dg__PreparingCellForEdit(object sender, DataGridPreparingCellForEditEventArgs e)
		{
			_isCellEditing++;
		}
		//------
		void dg__KeyDown(object sender, Input.KeyEventArgs e)
		{
			if(DataGrid == null || DataGrid.ItemsSource == null) return;
			if(_isCellEditing > 0) return; // edituje cell
			//------------------------------------------------	
			if(e.Key == Input.Key.Delete) {
				e.Handled = true;
				OnRemove(new HandledEventArgs());
			}
			if(!e.Handled && (e.Key == Input.Key.E) && (Input.Keyboard.Modifiers & Input.ModifierKeys.Control) > 0) {
				e.Handled = true;
				OnEditItem(new HandledEventArgs());
			}
			if(!e.Handled && (e.Key == Input.Key.F) && (Input.Keyboard.Modifiers & Input.ModifierKeys.Control) > 0) {
				string ss = string.Empty;
				// pokud není Ctrl-F
				//ss=e.Key.ToString();
				//if (ss.Length != 1 || !(char.IsDigit(ss, 0) || char.IsLetter(ss, 0))) return;
				// mam DataGrid
				// Test jestli je Column povolený
				DataGridTextColumn col = null;
				if(DataGrid.CurrentColumn != null) {
					col = DataGrid.CurrentColumn as DataGridTextColumn;
				} else col = _lastFilteredColumn;
				if(col != null) {
					var fi = ColumnsForFilteringInternal.FirstOrDefault(p => p.ColumnName == col.Binding.Path.Path);
					if(fi != null) {
						_lastFilteredColumn = col;
						//-- Je povolený k filtrování --
						if(!string.IsNullOrEmpty(ss)) {
							if((Input.Keyboard.Modifiers & Input.ModifierKeys.Shift) == 0) ss = char.ToLower(ss[0]).ToString();
						}
						//-- zobraz okno pro zadání parametru
						ShowFilterParametrPopup(ss, fi);
						e.Handled = true;
					}
				}
			}
		}
		//---  
		void dg__RowEditEnded(object sender, DataGridRowEditEndedEventArgs e)
		{
			// Submit
			if(AutoSubmit) {
				OnSubmitChanges(new HandledEventArgs());
			}
		}

		#endregion

		//------------------

	}
}
